<?php

namespace Lib\Model;

use Lib\Util\Inflector;

class Model {

    public $table;

    private $source;

    private $baseOptions = array(
        'conditions' => array(),
        'fields'     => array(),
        'group'      => '',
        'limit'      => 0,
        'page'       => 1,
        'order'      => ''
    );

    private $options;

    public $order;
    public $error;
    public $lastInsertId;

    public function __construct() {
        $class       = get_class($this);
        $this->name  = end(explode("\\", $class));
        $this->table = Inflector::pluralize(Inflector::underscore($this->name));

        $this->options = $this->baseOptions;
    }

    public function addCondition($field, $pattern) {
        $this->options['conditions'][$field] = $pattern;
        return $this;
    }

    public function find($options = array()) {
        $this->loadDatasource();
        $this->parseOptions($options);

        $this->source->connect();
        $result = $this->source->query($options);

        $this->source->close();

        return $result;
    }

    public function first($options = array()) {
        $options['limit'] = 1;
        $options['page'] = 1;
        return end($this->find($options));
    }

    public function get($id) {
        return $this->first(array(
            'conditions' => array( "{$this->name}.id" => $id)
        ));
    }

    public function save($data) {
        $this->source->connect();

        $sql = $this->data2sql($data);

        $saved = $this->source->execute($sql);
        $this->error = $saved ? null : $this->source->lastError();
        $this->lastInsertId = $this->source->lastInsertId();

        $this->source->close();
        return $saved;
    }

    public function saveAll($data) {
        $saved = false;
        $this->source->connect();

        $this->error = null;
        foreach ($data as $d) {
            $d = (object)$d;
            $sql = $this->data2sql($d);
            $s = $this->source->execute($sql);
            if (! $s) $this->error = $this->source->lastError();
            $saved = $saved || $s;
        }

        $this->source->close();
        return $saved;
    }

    public function delete($id) {
        $this->source->connect();

        $sql = "DELETE FROM {$this->table} WHERE id=" . $this->escape($id);
        $deleted = $this->source->execute($sql) ? true : false;
        $this->source->close();

        return $deleted;
    }

    private function loadDatasource() {
        $name = isset($this->datasource) ? $this->datasource : 'default';
        $this->source = Datasource::load($name, $this);
    }

    private function parseOptions(Array &$options) {
        $options = array_merge($this->baseOptions, $this->options, $options);
    }

    private function escape($string) {
        if (is_null($string)) {
            return 'NULL';
        }elseif (is_string($string)) {
            return "'" . $this->source->escape($string) . "'";
        } else {
            return $string;
        }
    }

    private function data2sql($data) {
        if (is_array($data)) {
            $data = (object)$data;
        }

        $id = (int)$data->id;
        unset($data->id);

        if (isset($id) &&  $id>0) {
            $sql = 'UPDATE ' . $this->table . ' SET ';
            foreach ($data as $field=>$value) {
                $sql .= $field . '=' . $this->escape($value) . ", ";
            }
            $sql = preg_replace('/, $/', '', $sql) . " WHERE id={$id}";
        } else {
            $fields = array_keys((array)$data);
            $sql = 'INSERT INTO ' . $this->table . '(`' . implode('`,`', $fields) . '`) '.
                   'VALUES(';
            foreach ($data as $field=>$value) {
                $sql .= $this->escape($value) . ", ";
            }
            $sql = preg_replace('/, $/', '', $sql) . ")";
        }

        return $sql;
    }

}